﻿using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Sustainalytics.Entities;
using Sustainalytics.LongRunningTaskManager;
using Sustainalytics.LongRunningTaskManager.Interface;
using Sustainalytics.OAuth.Services.Common.Client;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using Sustainalytics.Utils.Enumerable;

namespace Sustainalytics.Governance.Tasks
{
    public class GovernanceFileExportTask : ILongRunningTask
    {
        public LongRunningTaskTypeEnum Type => LongRunningTaskTypeEnum.GovernancePDF;

        public object Start(LongRunningTaskContext context)
        {
            var param = JsonConvert.DeserializeObject<FileExportDto>(context.ParamJson);

            if (param != null && param.FileType != "report")
                return GetFileFromDb(context);            

            return GetFileResult(context);
        }

        private ILongRunningTaskResult GetFileResult(LongRunningTaskContext context)
        {
            var param = JsonConvert.DeserializeObject<FileExportDto>(context.ParamJson);
            var companyId = new Guid(param.FileId);

            var url = ConfigurationManager.AppSettings["governanceUrl"];
            var uri = new Uri($"{url}/api/v1");

            return TryGetReportFromS3(context, uri, companyId);
        }

        private LongRunningTaskS3FileResult TryGetReportFromS3(LongRunningTaskContext context, Uri uri, Guid companyId)
        {
            if (uri == null)
                throw new ArgumentNullException("uri");

            if (companyId == null)
                throw new ArgumentNullException("companyId");

            try
            {
                var requestUri = $"{uri}/company/{companyId}/companyReport";

                var jsonMediaTypeFormatter = new JsonMediaTypeFormatter
                {
                    SerializerSettings =
                    {
                        ContractResolver = new CamelCasePropertyNamesContractResolver()
                    }
                };

                using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                    var executionResult = client.GetAsync(requestUri).Result;

                    if (executionResult.IsSuccessStatusCode)
                    {
                        var result = executionResult.Content.ReadAsAsync<GovernancePdfReport>(jsonMediaTypeFormatter.Yield()).Result;

                        if (result == null)
                        {
                            SetErrorToContext(context);
                            return null;
                        }

                        context.Title = result.FileName;
                        context.TaskStatus.Progress = 100;

                        return new LongRunningTaskS3FileResult
                        {
                            MimeType = "application/pdf",
                            Bucket = result.S3Bucket,
                            FileName = result.FileName,
                            Key = result.S3Key
                        };
                    }

                    SetErrorToContext(context);

                    LongRunningTaskManagerEventSource.Log.TaskFailed(LongRunningTaskTypeEnum.GovernancePDF, "", "",
                        $"Failed to get the Company Report for company ID={companyId}");
                }
            }
            catch (HttpRequestException httpRequestException)
            {
                LongRunningTaskManagerEventSource.Log.TaskFailed(LongRunningTaskTypeEnum.GovernancePDF, "", "", string.Format("Error {0}", httpRequestException));
                context.TaskStatus.AddError(new LongRunningTaskError
                {
                    ErrorCode = 7003,
                    Arguments = new List<string> { httpRequestException.Message }
                });
            }

            return null;
        }

        private void SetErrorToContext(LongRunningTaskContext context)
        {
            context.Title = "Failed to get the Company Report for specified company";
            context.TaskStatus.AddError(new LongRunningTaskError
            {
                ErrorCode = 7001,
                Arguments = new List<string> { "Failed to get the Company Report for specified company" }
            });
        }

        private ILongRunningTaskResult GetFileFromDb(LongRunningTaskContext context)
        {
            var param = JsonConvert.DeserializeObject<FileExportDto>(context.ParamJson);

            var oAuthClient = new OAuthClient(
                HostConfig.GetHostUrl() + HostConfig.GetFileResource() + "/token",
                HostConfig.GetHostUrl() + HostConfig.GetFileResource(),
                null);

            var reqPath = HostConfig.GetHostUrl() + HostConfig.GetFileResource() + "/" + param.FileId;

            if (!string.IsNullOrWhiteSpace(param.FileType))
            {
                reqPath += "?fileType=" + param.FileType;
            }
            else if (param.IsPdfProfile)
            {
                reqPath += "?fileType=profile";
            }            

            oAuthClient.SetAuthenticationTicket(context.Ticket);

            var resp = oAuthClient.GetAsync(reqPath).Result;

            resp.EnsureSuccessStatusCode();

            var fileName = resp.Content.Headers.ContentDisposition.FileName;
            var mimeType = resp.Content.Headers.ContentType.MediaType;
            var contents = resp.Content.ReadAsByteArrayAsync().Result;

            var file = new LongRunningTaskFileInMemResult
            {
                FileName = fileName,
                MimeType = mimeType,
                Contents = contents
            };

            return file;
        }

    }
}
